#region license
/*
 * Copyright (C) 2007 CchenSoft.com
 * 
 * This library is free software; you can redistribute it and/or modify it 
 * under the terms of the GNU Lesser General Public License 2.1 or later, as
 * published by the Free Software Foundation. See the included License.txt
 * or http://www.gnu.org/copyleft/lesser.html for details.
 * 
 * Author: Billy Zhang
 */
#endregion

using System;
using System.Web;
using System.Collections.Specialized;
using System.Collections;
using System.Reflection;
using CchenSoft.Common.Utils;

namespace CchenSoft.Workflow.Util
{
    public class BeanUtils
    {
        //~ Static fields/initializers /////////////////////////////////////////////

        static BeanUtils()
        {
        }

        //~ Methods ////////////////////////////////////////////////////////////////

        /**
         * Get list of property names of bean.
         *
         * @param obj Object to query for property names.
         * @return Array of property names, or null if an error occurred.
         */
        public static string[] GetPropertyNames(object obj)
        {
            try
            {
                PropertyInfo[] properties = obj.GetType().GetProperties();
                string[] result = new string[properties.Length];

                for (int i = 0; i < properties.Length; i++)
                {
                    result[i] = properties[i].Name;
                }

                return result;
            }
            catch (Exception e)
            {
                return null;
            }
        }

        /**
         * Set a single property of the bean.
         *
         * @param obj The object to be manipulated.
         * @param property Name of property to set.
         * @param value Value to set property to.
         * @return Boolean indicating success.
         */
        public static bool SetValue(object obj, string property, object value)
        {
            return ReflectUtil.SetProperty(obj, property, value);
        }

        /**
         * Get a single property of the bean.
         *
         * @param obj The object to be accessed.
         * @param property Name of property to get.
         * @return Value of property. If property was not found, null is returned.
         */
        public static object GetValue(object obj, string property)
        {
            return ReflectUtil.GetProperty(obj, property);
        }

        /**
         * Set multiple properties of a bean at once using a Map. Any unknown properties
         * shall be ignored.
         *
         * @param obj The object to be manipulated.
         * @param valueMap Map containing property-name (String) / property-value (Object)
         *        pairs to set in the object.
         * @param allowedProperties If array is NOT null, only the properties matching names
         *        passed here shall be set.
         */
        public static void SetValues(object obj, IDictionary valueMap, string[] allowedProperties)
        {
            foreach (string property in valueMap.Keys)
            {
                if (allowed(property, allowedProperties))
                {
                    SetValue(obj, property, valueMap[property]);
                }
            }
        }

        /**
         * Set multiple properties of a bean at once using properties of another bean.
         * The beans may be of different types and any properties not common to both types
         * shall be ignored.
         *
         * @param obj The object to be manipulated.
         * @param src The object containing the properties to be copied.
         * @param allowedProperties If array is NOT null, only the properties matching names
         *        passed here shall be set.
         */
        public static void SetValues(object obj, object src, string[] allowedProperties)
        {
            SetValues(obj, GetValues(src, allowedProperties), allowedProperties);
        }

        /**
         * Set multiple properties of a bean at once using the params passed across
         * from the ServletRequest (useful for mapping HTML forms to beans). Any properties
         * not known shall be ignored.
         *
         * @param obj The object to be manipulated.
         * @param request ServletRequest to get params from.
         * @param allowedProperties If array is NOT null, only the properties matching names
         *        passed here shall be set.
         */
        public static void SetValues(object obj, HttpRequest request, string[] allowedProperties)
        {
            Hashtable parameters = new Hashtable();
            NameValueCollection paramColl = request.Params;

            foreach (string name in paramColl.Keys)
            {
                parameters[name] = paramColl[name];
            }

            SetValues(obj, parameters, allowedProperties);
        }

        /**
         * Get Map of property values from a bean.
         *
         * @param obj Object to query for properties.
         * @param allowedProperties If array is NOT null, only the properties matching names
         *        passed here shall be retrieved.
         * @return Map containing property-name (String) / property-value (Object) pairs.
         */
        public static IDictionary GetValues(object obj, string[] allowedProperties)
        {
            Hashtable result = new Hashtable();
            String[] propertyNames = GetPropertyNames(obj);

            for (int i = 0; i < propertyNames.Length; i++)
            {
                String propertyName = propertyNames[i];
                Object propertyValue = GetValue(obj, propertyName);

                if ((propertyName == null) || (propertyValue == null))
                {
                    continue;
                }

                if (allowed(propertyName, allowedProperties))
                {
                    result[propertyName] = propertyValue;
                }
            }

            return result;
        }

        private static bool allowed(string str, string[] array)
        {
            if (array == null)
            {
                return true;
            }

            if (str == null)
            {
                return false;
            }

            for (int i = 0; i < array.Length; i++)
            {
                if (str.Equals(array[i]))
                {
                    return true;
                }
            }

            return false;
        }
    }
}
